package game.script;

import haxe.ValueException;
import hscript.Expr;
import haxe.Exception;
import hscript.Parser;
import hscript.Interp;

using StringTools;
using game.script.ScriptTools;

/**
 * 脚本实现
 */
class Script {
	public var classes:Map<String, Class<Dynamic>> = new Map();

	public var functions:Map<String, ScriptFunction> = new Map();

	public var vars:Map<String, Dynamic> = [];

	public var fileName:String;

	public var variables:Map<String, Dynamic> = [];

	public function new(self:Dynamic, fileName:String, source:String):Void {
		this.fileName = fileName;
		this.variables.set("this", self);
		for (key in Reflect.fields(self)) {
			this.variables.set(key, Reflect.getProperty(self, key));
		}
		if (source != null) {
			parser(source);
		}
	}

	/**
	 * 解析脚本
	 * @param source 
	 */
	private function parser(source:String):Void {
		// 解析import语句
		var imports = ~/import [a-z.A-Z]+;/g;
		imports.map(source, (f) -> {
			var className = f.matched(0);
			importClasses(className);
			return className;
		});
		// 将类名和结尾删除
		source = source.outBlock();
		// 解析方法
		var code = source.split("\n");
		var counts = 0;
		var funcCodes = [];
		for (line in code) {
			if (counts == 0 && line.indexOf("var ") != -1) {
				var varName = line.readVarName();
				var varData = line.readVarData(this);
				this.vars.set(varName, varData);
				this.variables.set(varName, varData);
			}

			if (line.indexOf("{") != -1) {
				counts++;
			}
			if (counts > 0) {
				// 处于函数实现
				funcCodes.push(line);
			} else {}
			if (line.indexOf("}") != -1) {
				counts--;
				if (counts == 0) {
					var func = new ScriptFunction(this, funcCodes.join("\n"));
					this.functions.set(func.name, func);
					this.variables.set(func.name, func.call);
					funcCodes = [];
				}
			}
		}
	}

	/**
	 * 导入类型实现
	 * @param classesName 
	 */
	public function importClasses(classesName:String):Void {
		var cName = classesName.replace("import ", "").replace(";", "");
		var clazz = Type.resolveClass(cName);
		var name = cName.split(".").pop();
		classes.set(name, clazz);
		this.variables.set(name, clazz);
	}

	public function execute(expr:Expr):Dynamic {
		var interp:Interp = new Interp();
		for (key => value in this.variables) {
			interp.variables.set(key, value);
		}
		var e = interp.execute(expr);
		for (key => _ in vars) {
			vars.set(key, interp.variables.get(key));
			variables.set(key, interp.variables.get(key));
		}
		return e;
	}
}

class ScriptFunction {
	/**
	 * 方法名称
	 */
	public var name:String;

	/**
	 * 代码实现
	 */
	public var code:String;

	/**
	 * 方法调用
	 */
	public var expr:Expr;

	public var script:Script;

	public var args:Array<String>;

	public function new(i:Script, code:String):Void {
		this.script = i;
		// 需要转换一下this.var的变量为var
		for (key => _ in i.vars) {
			code = code.replace("this." + key, key);
		}
		var funcName = ~/function .+\(/;
		funcName.match(code);
		this.name = funcName.matched(0).replace("function ", "").replace("(", "");
		// 参数
		this.args = code.readArgs();
		this.code = code.outBlock().removeSuperCode();
		// 追加参数
		try {
			var hscript:Parser = new Parser();
			hscript.allowTypes = true;
			hscript.allowJSON = true;
			hscript.allowMetadata = true;
			expr = hscript.parseString(this.code);
		} catch (e:Exception) {
			logException(e);
		}
	}

	/**
	 * 方法调用
	 * @param ...args 
	 * @return Dynamic
	 */
	public function call(...args):Dynamic {
		try {
			var array = args.toArray();
			for (index => _ in args) {
				// this.script.variables.set("___" + this.name + "_" + index, array[index]);
				this.script.variables.set(this.args[index], array[index]);
			}
			return this.script.execute(expr);
		} catch (e:Exception) {
			logException(e);
			return null;
		}
	}

	public function logException(e:Exception) {
		#if (game || game_develop || editer)
		hx.utils.Log.exceptionHscirpt(cast e, this.script.fileName, this.name, this.code);
		#else
		var message:String = e.message;
		trace("Script error:", message);
		#end
	}
}
